use std::fmt::Display;

use quic_secs_driver::secs2::Message;
use serde::{Deserialize, Serialize};
use tauri::{WebviewWindow, Window};

use crate::helper;

#[derive(Serialize, Deserialize, Clone)]
pub(crate) struct TransactionTemplate {
    #[serde(default = "helper::get_transaction_id")]
    pub(crate) id: String,
    pub(crate) name: Option<String>,
    pub(crate) desc: Option<String>,
    pub(crate) primary: Message,
    pub(crate) secondary: Option<Message>,
    pub(crate) match_rules: Option<Vec<MatchRule>>,
    pub(crate) reply_secondary: bool,
    pub(crate) send_primary: Option<Vec<String>>,
}

impl TransactionTemplate {
    pub(crate) fn to_json_without_id(&self) -> serde_json::Value {
        serde_json::json!({
            "name":self.name,
            "desc":self.desc,
            "primary":self.primary,
            "secondary":self.secondary,
            "match_rules":self.match_rules,
            "reply_secondary":self.reply_secondary,
            "send_primary":self.send_primary,
        })
    }
}

#[derive(Serialize, Deserialize, Clone)]
pub(crate) struct MatchRule {
    pub(crate) name: Option<String>,
    pub(crate) format: Option<String>,
    pub(crate) value: Option<String>,
}

#[allow(dead_code)]
pub(crate) enum MatchPolicy {
    None,
    Format,
    FormatAndValue,
}

#[derive(Serialize, Deserialize)]
pub(crate) struct WindowState {
    x: i32,
    y: i32,
    width: u32,
    height: u32,
    is_maximized: bool,
}

impl WindowState {
    pub(crate) fn from_window(win: &Window) -> Self {
        let (x, y) = match win.outer_position() { Ok(pos) => {
            (pos.x, pos.y)
        } _ => {
            (0, 0)
        }};
        let (width, height) = match win.inner_size() { Ok(pos) => {
            (pos.width, pos.height)
        } _ => {
            (800, 600)
        }};
        Self {
            x,
            y,
            width,
            height,
            is_maximized: win.is_maximized().unwrap_or(false),
        }
    }

    pub(crate) fn save(win: &Window) {
        let window_state = WindowState::from_window(&win);
        if let Ok(json) = serde_json::to_string(&window_state) {
            let mut path = crate::get_root().join("conf");
            if !path.exists() {
                if let Err(_) = std::fs::create_dir_all(&path) {
                    return;
                }
            }
            path.push(".win_state");
            _ = std::fs::write(path, json.as_bytes());
        }
    }

    pub(crate) fn restore(win: &WebviewWindow) {
        let path = crate::get_root().join("conf").join(".win_state");
        if !path.exists() {
            return;
        }

        if let Ok(json) = std::fs::read_to_string(path) {
            if let Ok(mut window_state) = serde_json::from_str::<WindowState>(&json) {
                if window_state.width < 400 {
                    window_state.width = 400;
                }
                if window_state.height < 300 {
                    window_state.height = 300;
                }
                _ = win.set_size(tauri::LogicalSize::new(
                    window_state.width,
                    window_state.height,
                ));
                if window_state.x < 0 {
                    window_state.x = 0;
                }
                if window_state.y < 0 {
                    window_state.y = 0;
                }
                if let Ok(Some(monitor)) = win.current_monitor() {
                    let size = monitor.size();
                    if window_state.x > size.width as i32 {
                        window_state.x = 0;
                    }
                    if window_state.y > size.height as i32 {
                        window_state.y = 0;
                    }
                }
                _ = win.set_position(tauri::LogicalPosition::new(window_state.x, window_state.y));
            }
        }
    }
}

#[derive(Deserialize, Serialize, Clone)]
pub(crate) struct Preference {
    pub(crate) log: PreferenceLog,

    #[serde(rename = "collectionEvent")]
    pub(crate) collection_event: CollectionEvent,

    pub(crate) variable: Variable,

    pub(crate) mappings: Vec<MappingItem>,
}

impl Default for Preference {
    fn default() -> Self {
        Self {
            log: Default::default(),
            collection_event: Default::default(),
            variable: Default::default(),
            mappings: vec![],
        }
    }
}

#[derive(Deserialize, Serialize, Clone)]
pub(crate) struct PreferenceLog {
    pub(crate) dir: String,

    #[serde(rename = "fileMaxSize")]
    pub(crate) file_max_size: u64,

    #[serde(rename = "messageMaxSize")]
    pub(crate) message_max_size: u64,

    #[serde(rename = "outputMaxSize")]
    pub(crate) output_max_size: u64,

    #[serde(rename = "isWriteSecs1")]
    pub(crate) is_write_secs1: bool,
}

impl Default for PreferenceLog {
    fn default() -> Self {
        Self {
            dir: String::from("logs"),
            file_max_size: 50 * 1024 * 1024,
            message_max_size: 2000,
            output_max_size: 2000,
            is_write_secs1: true,
        }
    }
}

#[derive(Serialize, Deserialize, Clone)]
pub(crate) struct CollectionEvent {
    pub(crate) messages: Vec<MessageFlag>,
    pub(crate) items: Vec<CollectionEventItem>,
}

impl CollectionEvent {
    pub(crate) fn is_match_message(&self, s: u8, f: u8) -> bool {
        for item in self.messages.iter() {
            if item.stream.is_match(s) && item.function.is_match(f) {
                return true;
            }
        }
        false
    }

    // pub(crate) fn fill_ceid(&self, message: &mut Message) -> bool {
    //     if !self.is_match_message(message.head.stream, message.head.function) {
    //         return false;
    //     }
    //     if let Some(val) = message.body.as_mut() {
    //         helper::fill_ceid(val, &self.items);
    //     }
    //     return true;
    // }
}

impl Default for CollectionEvent {
    fn default() -> Self {
        Self {
            messages: Default::default(),
            items: Default::default(),
        }
    }
}

#[derive(Serialize, Deserialize, Clone)]
pub(crate) struct CollectionEventItem {
    pub(crate) key: String,
    pub(crate) id: String,
    pub(crate) desc: String,
    pub(crate) format: String,
}

#[derive(Clone)]
pub(crate) struct MessageFlag {
    stream: MessageFlagPattern,
    function: MessageFlagPattern,
}

#[derive(Clone)]
pub(super) enum MessageFlagPattern {
    Exact(u8),
    Range(u8, u8),
    Any,
}

impl MessageFlagPattern {
    pub(crate) fn is_match(&self, value: u8) -> bool {
        match self {
            MessageFlagPattern::Exact(a) => a == &value,
            MessageFlagPattern::Range(a, b) => &value >= a && &value <= b,
            MessageFlagPattern::Any => true,
        }
    }
}

impl Display for MessageFlagPattern {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            MessageFlagPattern::Exact(val) => f.write_str(&val.to_string()),
            MessageFlagPattern::Range(min, max) => f.write_fmt(format_args!("{min}-{max}")),
            MessageFlagPattern::Any => f.write_str("*"),
        }
    }
}

impl Serialize for MessageFlag {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        serializer.serialize_str(&format!("S{}F{}", self.stream, self.function))
    }
}

impl<'de> Deserialize<'de> for MessageFlag {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        struct MessageFlagVisitor;
        impl<'de> serde::de::Visitor<'de> for MessageFlagVisitor {
            type Value = MessageFlag;

            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                formatter.write_str("format [SxFx] is invalid")
            }

            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where
                E: serde::de::Error,
            {
                let str = v.to_uppercase();
                let str_len = str.len() - 1;
                let s_index = str.find("S").ok_or_else(|| {
                    serde::de::Error::custom(format!("couldn't find S in secs pattern:{str}"))
                })?;
                let f_index = str.find("F").ok_or_else(|| {
                    serde::de::Error::custom(format!("couldn't find F in secs pattern:{str}"))
                })?;
                if s_index != 0 || s_index == str_len || f_index < 1 || f_index == str_len {
                    return Err(serde::de::Error::custom(format!(
                        "the secs pattern format is error, value = {}",
                        str
                    )));
                }
                let stream = {
                    let v = &str[1..f_index];
                    if v == "*" {
                        MessageFlagPattern::Any
                    } else {
                        if let Some((v1, v2)) = v.split_once("-") {
                            helper::parse_to_range("stream", v1, v2, &str)?
                        } else {
                            helper::parse_to_exact("stream", v, &str)?
                        }
                    }
                };
                let function = {
                    let v = &str[(f_index + 1)..];
                    if v == "*" {
                        MessageFlagPattern::Any
                    } else {
                        if let Some((v1, v2)) = v.split_once("-") {
                            helper::parse_to_range("function", v1, v2, &str)?
                        } else {
                            helper::parse_to_exact("function", v, &str)?
                        }
                    }
                };
                Ok(MessageFlag { stream, function })
            }
        }
        deserializer.deserialize_str(MessageFlagVisitor)
    }
}

#[derive(Serialize, Deserialize, Clone)]
pub(crate) struct Variable {
    pub(crate) messages: Vec<MessageFlag>,
    pub(crate) items: Vec<VariableItem>,
}

impl Variable {
    pub(crate) fn is_match_message(&self, s: u8, f: u8) -> bool {
        for item in self.messages.iter() {
            if item.stream.is_match(s) && item.function.is_match(f) {
                return true;
            }
        }
        false
    }
}

impl Default for Variable {
    fn default() -> Self {
        Self {
            messages: Default::default(),
            items: Default::default(),
        }
    }
}

#[derive(Serialize, Deserialize, Clone)]
pub(crate) struct VariableItem {
    pub(crate) key: String,
    pub(crate) id: String,
    pub(crate) desc: String,
    pub(crate) format: String,
    pub(crate) mappings: Vec<ValueMapping>,
}

#[derive(Serialize, Deserialize, Clone)]
pub(crate) struct MappingItem {
    pub(crate) key: String,
    pub(crate) name: String,
    pub(crate) desc: String,
    pub(crate) mappings: Vec<ValueMapping>,
}

#[derive(Serialize, Deserialize, Clone)]
pub(crate) struct ValueMapping {
    pub(crate) key: String,
    pub(crate) value: String,
    pub(crate) desc: String,
    pub(crate) format: String,
}
